import 'dart:io';

import 'package:udp/udp.dart';

class UdpSocket {
  static final UdpSocket _singleton = UdpSocket._internal();
  static UdpSocket get instance => UdpSocket();
  factory UdpSocket() {
    return _singleton;
  }
  UdpSocket._internal();

  UDP? sender;

  String localAddress = '255.255.255.255';
  int localPort = 9090;
  static var mStream;

  /// 打开/关闭网关4g ON/OFF
  String control4g(String off) =>
      '\$sys/product/usr/control/pub{"messageId":"1234","params": {"key":"4G","ts":"1528292272000","info": [{"key":"earTagRep","value": $off}]}}';

  /// 检测网关ip地址
  String address = '';

  /// 网关端口
  var port = 0;
  RawDatagramSocket? senderSocket;

  /// 1. 绑定网关
  void startConnect() async {
    senderSocket = await RawDatagramSocket.bind(InternetAddress(localAddress, type: InternetAddressType.IPv4), localPort);
    senderSocket?.broadcastEnabled = true;
    senderSocket?.readEventsEnabled = true;
    // mStream = senderSocket?.asBroadcastStream();
    // mStream.listen(onSocketData,onError:);
    // senderSocket?.listen(onSocketData,onError: onSocketError,onDone: onSocketDone);

    senderSocket?.listen((e) {
      Datagram? dg = senderSocket?.receive();
      if (dg != null) {
        /// 检测消息，如果接受消息的端口不是9090 255.255.255.255 就说明是 网关发送的消息
        /// 记录地址，端口号，用于发送消息
        if (dg.address.address != localAddress && (address != dg.address.address || port != dg.port)) {
          address = dg.address.address;
          port = dg.port;
        }
        print("received ${String.fromCharCodes(dg.data)}");
        String dataStr = String.fromCharCodes(dg.data);
        // 心跳/ 网关推送消息
        if (dataStr.contains('sys/product/usr/earTag')) {
          print("received ${String.fromCharCodes(dg.data)}");
        } else if (dataStr.contains('')) {
          // 网关响应的json 数据
          // 解析json
        }
      }
    });
  }

  // socket事件
  void onSocketData(RawSocketEvent e) {
    switch (e) {
      //read 接收事件
      case RawSocketEvent.read:
        {
          Datagram? dg = senderSocket?.receive();
          if (dg != null) {
            /// 检测消息，如果接受消息的端口不是9090 255.255.255.255 就说明是 网关发送的消息
            /// 记录地址，端口号，用于发送消息
            if (dg.address.address != localAddress && (address != dg.address.address || port != dg.port)) {
              address = dg.address.address;
              port = dg.port;
            }
            print("received ${String.fromCharCodes(dg.data)}");
            String dataStr = String.fromCharCodes(dg.data);
            // 心跳/ 网关推送消息
            if (dataStr.contains('sys/product/usr/earTag')) {
              print("received ${String.fromCharCodes(dg.data)}");
            } else if (dataStr.contains('')) {
              // 网关响应的json 数据
              // 解析json
            }
          }
        }
        break;
      //write 发送事件
      case RawSocketEvent.write:
        {
          print('RawSocketEvent.write');
        }
        break;
      case RawSocketEvent.readClosed:
        {
          print('RawSocketEvent.readClosed');
        }
        break;
      case RawSocketEvent.closed:
        {
          print('RawSocketEvent.closed');
        }
        break;
    }
  }

  // socket关闭
  void onSocketDone() {
    senderSocket?.close();
    print('----[socket utils]----socket关闭');
  }

  // socket错误
  void onSocketError(Object error) {
    print('----[socket utils]----socket出现错误，error=${error.toString()}');
  }

  /// 2.绑定网关2
  void bindUdp() async {
    sender = await UDP.bind(Endpoint.any(port: const Port(9090)));
    sender?.asStream(timeout: const Duration(seconds: 10)).listen((datagram) async {
      var str = String.fromCharCodes(datagram!.data);
      print(str);
      stdout.write(str);
      address = datagram.address.address;
      port = datagram.port;
    });
  }

  /// 打开关闭4g
  void off4g(String ON) async {
    String str = '\$sys/product/usr/control/pub{"messageId":"100000","params": {"key":"4G","ts":"1528292272000","info": [{"key":"earTagRep","value": $ON}]}}';
    print('send :' + str);
    senderSocket?.send(str.codeUnits, InternetAddress(address), port);
    return;
  }
  void closeUdp() {
    sender?.close();
  }
}
